package gin

import (
	"fmt"
	"mime"
	"net/http"
	"strconv"
	"strings"
	"sync"

	"gitee.com/tomatomeatman/golang-repository/bricks/model"
	Log "github.com/cihub/seelog"
	"github.com/gin-contrib/static"
	"github.com/gin-gonic/gin"
)

type GinUtil struct{}

// 请求类型枚举
type RequestType string

const (
	GET     RequestType = "GET"
	POST    RequestType = "POST"
	DELETE  RequestType = "DELETE"
	PUT     RequestType = "PUT"
	OPTIONS RequestType = "OPTIONS"
)

// 枚举转字符串
func (rt RequestType) String() string {
	switch rt {
	case GET:
		return "GET"
	case POST:
		return "POST"
	case DELETE:
		return "DELETE"
	case PUT:
		return "PUT"
	case OPTIONS:
		return "OPTIONS"
	default:
		return "NA"
	}
}

var (
	guiUtil_UrlRegeditWg sync.WaitGroup                    //同步原语,要保证所有的Url注册都已经完成
	guiUtil_CheckWrite   sync.Mutex                        //保存锁
	httpHandleFunc       = make(map[string]HttpHandleInfo) //http控制层接口信息集合
)

// http控制层接口信息
type HttpHandleInfo struct {
	Url  string
	Type RequestType
	Fun  func(ctx *gin.Context) interface{}
}

// 设置跨域
func (gu GinUtil) SetCors(r *gin.Engine) {
	r.Use(gu.Cors())
}

func GetGin(ginMode, webRoot string, InterceptorFunc func(ctx *gin.Context) bool, shutdown func(ctx *gin.Context)) *gin.Engine {
	ginUtil := GinUtil{}

	HttpHandleInfos := ginUtil.GetController()

	switch strings.ToUpper(ginMode) { //gin运行模式
	case "RELEASE":
		gin.SetMode(gin.ReleaseMode)
		break
	case "TEST":
		gin.SetMode(gin.TestMode)
		break
	case "DEBUG":
		gin.SetMode(gin.DebugMode)
		break
	default:
		gin.SetMode(gin.ReleaseMode)
	}

	r := gin.Default()

	ginUtil.SetCors(r)                //设置跨域
	ginUtil.SetStatic(r, "."+webRoot) //设置静态目录

	r.GET("/shutdown", shutdown)
	r.POST("/shutdown", shutdown)

	for _, val := range HttpHandleInfos {
		switch val.Type {
		case GET:
			r.GET(val.Url, ginUtil.GetHandleFunc(val.Url, GET, InterceptorFunc, HttpHandleInfos))
			break
		case POST:
			r.POST(val.Url, ginUtil.GetHandleFunc(val.Url, POST, InterceptorFunc, HttpHandleInfos))
			break
		case DELETE:
			r.DELETE(val.Url, ginUtil.GetHandleFunc(val.Url, DELETE, InterceptorFunc, HttpHandleInfos))
			break
		case PUT:
			r.PUT(val.Url, ginUtil.GetHandleFunc(val.Url, PUT, InterceptorFunc, HttpHandleInfos))
			break
		case OPTIONS:
			r.OPTIONS(val.Url, ginUtil.GetHandleFunc(val.Url, OPTIONS, InterceptorFunc, HttpHandleInfos))
			break
		default:
			r.GET(val.Url, func(ctx *gin.Context) {
				ctx.JSONP(http.StatusBadRequest, model.MsgEmity{}.Err(1001, "请求方式错误,不支持此方式"))
			})
		}
	}

	httpHandleFunc = make(map[string]HttpHandleInfo) //清理

	return r
}

// 跨域函数
func (gu GinUtil) Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin")
		if origin != "" {
			c.Header("Access-Control-Allow-Origin", "*") // 可将将 * 替换为指定的域名
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
			//c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
			//c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
			c.Header("Access-Control-Allow-Headers", "*")
			c.Header("Access-Control-Expose-Headers", "*")
			c.Header("Access-Control-Allow-Credentials", "true")
		}
		if method == "OPTIONS" {
			c.AbortWithStatus(http.StatusNoContent)
		}
		c.Next()
	}
}

// 设置静态路径
func (gu GinUtil) SetStatic(r *gin.Engine, webroot string) {
	_ = mime.AddExtensionType(".js", "application/javascript") // 特殊处理JS文件的Content-Type
	r.Use(static.Serve("/", static.LocalFile(webroot, true)))  // 前端项目静态资源
}

// 注册web接口
func (gu GinUtil) RegisterController(url string, iTypes interface{}, handler func(ctx *gin.Context) interface{}) {
	gu.RegisterControllers(url, iTypes, handler)
}

// 注册web接口
func (gu GinUtil) ControllerRegister(url string, handler func(ctx *gin.Context) interface{}, iTypes ...RequestType) {
	if len(iTypes) < 1 {
		gu.registerController(url, POST, handler)
		return
	}

	for _, rt := range iTypes {
		gu.registerController(url, rt, handler)
	}
}

// 注册web接口
func (gu GinUtil) RegisterControllers(url string, iTypes interface{}, handler func(ctx *gin.Context) interface{}) {
	switch t := iTypes.(type) {
	case RequestType:
		gu.registerController(url, t, handler)
	case []RequestType:
		if len(iTypes.([]RequestType)) < 1 {
			gu.registerController(url, POST, handler)
			return
		}

		for _, v := range iTypes.([]RequestType) {
			gu.registerController(url, v, handler)
		}
	default:
		gu.registerController(url, POST, handler)
	}
}

// 注册web接口
func (gu GinUtil) registerController(url string, iType RequestType, handler func(ctx *gin.Context) interface{}) {
	guiUtil_UrlRegeditWg.Add(1)       // 注册前增加计数器
	defer guiUtil_UrlRegeditWg.Done() // 注册结束时减少计数器

	guiUtil_CheckWrite.Lock()         //加锁
	defer guiUtil_CheckWrite.Unlock() //解锁

	temp := url + iType.String()
	_, ok := httpHandleFunc[temp]
	if ok {
		Log.Error("链接重复:" + url)
		return
	}

	httpHandleFunc[temp] = HttpHandleInfo{
		Url:  url,
		Type: iType,
		Fun:  handler,
	}
}

// 取注册的web接口
func (gu GinUtil) GetController() map[string]HttpHandleInfo {
	guiUtil_UrlRegeditWg.Wait() // 等待所有注册完成
	return httpHandleFunc
}

// 取注册的web接口
func (gu GinUtil) GetHandleFunc(urlKey string, iType RequestType, InterceptorFunc func(ctx *gin.Context) bool,
	controllerMap map[string]HttpHandleInfo) func(ctx *gin.Context) {
	result := func(ctx *gin.Context) {
		urlStr := ctx.Request.URL.Path

		if nil != InterceptorFunc {
			if !InterceptorFunc(ctx) {
				return
			}
		}

		var urlAndType string
		if strings.HasPrefix(urlStr, "/proxy/") { //路径中存在转发请求
			urlAndType = "/proxy/*proxy" + iType.String()
		} else {
			urlAndType = urlKey + iType.String() //url和请求方式组合
		}

		httpHandleInfo, ok := controllerMap[urlAndType] //给个默认
		if !ok {
			return
		}
		// for runKey := range controllerMap {
		// 	if runKey != urlStr {
		// 		continue
		// 	}

		// 	httpHandleInfo = controllerMap[urlAndType]
		// 	vb = true
		// 	break
		// }

		// if !vb {
		// 	return
		// }

		obj := httpHandleInfo.Fun(ctx)
		switch obj.(type) {
		case *model.MsgEmity, model.MsgEmity:
			ctx.JSONP(http.StatusOK, obj)
			break
		case *model.FileEmity:
			fm := obj.(*model.FileEmity)
			if !fm.Gsuccess {
				ctx.JSONP(http.StatusOK, obj)
				break
			}

			if fm.Gdisposition != "" {
				ctx.Header("Content-Disposition", fm.Gdisposition)
			}

			ctx.Header("Content-Type", fm.Gtype)
			ctx.Header("Content-Length", fm.GsLength)
			ctx.Writer.Write(fm.Gdata.([]byte))
			break
		case model.FileEmity:
			fm := obj.(model.FileEmity)
			if !fm.Gsuccess {
				ctx.JSONP(http.StatusOK, obj)
				break
			}

			if fm.Gdisposition != "" {
				ctx.Header("Content-Disposition", fm.Gdisposition)
			}

			ctx.Header("Content-Type", fm.Gtype)
			ctx.Header("Content-Length", fm.GsLength)
			ctx.Writer.Write(fm.Gdata.([]byte))
			break
		case []byte:
			by := obj.([]byte)
			ctx.Header("Content-Type", "application/octet-stream")
			ctx.Header("Content-Length", strconv.Itoa(len(by)))
			ctx.Writer.Write(by)
			break
		default:
			ctx.Writer.Write([]byte(fmt.Sprintf("%v", obj)))
		}
	}

	return result
}

// // 关闭服务
// func (gu GinUtil) Shutdown(ctx *gin.Context) {
// 	key := url.UrlUtil{}.GetParam(ctx, "sInsideKey", "").(string)
// 	if "" == key {
// 		ctx.JSONP(http.StatusOK, model.MsgEmity{}.Err(100001, "请求密钥参数sInsideKey缺失"))
// 		return
// 	}

// 	appKey := app.AppUtil{}.ReadConfigKey("App", "InsideKey", "12345").(string)
// 	if appKey != key {
// 		ctx.JSONP(http.StatusOK, model.MsgEmity{}.Err(100001, "请求密钥参数错误"))
// 		return
// 	}

// 	Log.Debug("关闭服务...")

// 	if err := appGinServer.Shutdown(ctx); err != nil {
// 		Log.Debug("服务强制关闭发生异常:", err)
// 		ctx.JSONP(http.StatusOK, model.MsgEmity{}.Err(100003, "服务强制关闭发生异常"))
// 		return
// 	}

// 	fmt.Println("服务关闭")
// 	ctx.JSONP(http.StatusOK, model.MsgEmity{}.Success(9999, "服务强制关闭成功"))
// }
